package com.wsjc.common.redis;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.wsjc.common.redis.cluster.JedisClusterInstance;

import redis.clients.jedis.JedisCluster;

/**
 * @描述: Redis缓存工具类.
 */
@Component("redisClusterUtils")
public class RedisClusterUtils {

	private Logger logger = Logger.getLogger(RedisClusterUtils.class);

	/** 默认缓存时间 */
	private final int DEFAULT_CACHE_SECONDS = 60 * 60 * 1;// 单位秒 设置成一个钟

	private static JedisCluster jedisCluster ;

	public RedisClusterUtils() {
	}
	

	/**
	 * 释放redis资源
	 * 
	 * @param jedisCluster
	 */
	private void releaseResource(JedisCluster jedisCluster) {
		
		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			if (jedisCluster != null) {
				jedisCluster.close();
			}
		} catch (IOException e) {
			logger.error("关闭jedisCluster失败：", e);
		}
	}

	/**
	 * 删除Redis中的所有key
	 * 
	 * @param jedisCluster
	 * @throws Exception
	 */
	@SuppressWarnings("deprecation")
	public void flushAll() {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.flushDB();
		} catch (Exception e) {
			logger.error("Cache清空失败：", e);
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 保存一个对象到Redis中(缓存过期时间:使用此工具类中的默认时间) . <br/>
	 * 
	 * @param key
	 *            键 . <br/>
	 * @param object
	 *            缓存对象 . <br/>
	 * @return true or false . <br/>
	 * @throws Exception
	 */
	public Boolean save(Object key, Object object) {
		return save(key, object, DEFAULT_CACHE_SECONDS);
	}

	/**
	 * 保存一个对象到redis中并指定过期时间
	 * 
	 * @param key
	 *            键 . <br/>
	 * @param object
	 *            缓存对象 . <br/>
	 * @param seconds
	 *            过期时间（单位为秒）.<br/>
	 * @return true or false .
	 */
	public Boolean save(Object key, Object object, int seconds) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.set(SerializeUtils.serialize(key), SerializeUtils.serialize(object));
			jedisCluster.expire(SerializeUtils.serialize(key), seconds);
			return true;
		} catch (Exception e) {
			logger.error("Cache保存失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 根据缓存键获取Redis缓存中的值.<br/>
	 * 
	 * @param key
	 *            键.<br/>
	 * @return Object .<br/>
	 * @throws Exception
	 */
	public Object get(Object key) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			byte[] obj = jedisCluster.get(SerializeUtils.serialize(key));
			return obj == null ? null : SerializeUtils.unSerialize(obj);
		} catch (Exception e) {
			logger.error("Cache获取失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 根据缓存键清除Redis缓存中的值.<br/>
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public Boolean del(Object key) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.del(SerializeUtils.serialize(key));
			return true;
		} catch (Exception e) {
			logger.error("Cache删除失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 根据缓存键清除Redis缓存中的值.<br/>
	 * 
	 * @param keys
	 * @return
	 * @throws Exception
	 */
	public Boolean del(Object... keys) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.del(SerializeUtils.serialize(keys));
			return true;
		} catch (Exception e) {
			logger.error("Cache删除失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 
	 * @param key
	 * @param seconds
	 *            超时时间（单位为秒）
	 * @return
	 */
	public Boolean expire(Object key, int seconds) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.expire(SerializeUtils.serialize(key), seconds);
			return true;
		} catch (Exception e) {
			logger.error("Cache设置超时时间失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 添加一个内容到指定key的hash中
	 * 
	 * @param key
	 * @param field
	 * @param value
	 * @return
	 */
	public Boolean addHash(String key, Object field, Object value) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			jedisCluster.hset(SerializeUtils.serialize(key), SerializeUtils.serialize(field),
					SerializeUtils.serialize(value));
			return true;
		} catch (Exception e) {
			logger.error("Cache保存失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 从指定hash中拿一个对象
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public Object getHash(Object key, Object field) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			byte[] obj = jedisCluster.hget(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
			return SerializeUtils.unSerialize(obj);
		} catch (Exception e) {
			logger.error("Cache读取失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 从hash中删除指定filed的值
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public Boolean delHash(Object key, Object field) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			long result = jedisCluster.hdel(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
			return result == 1 ? true : false;
		} catch (Exception e) {
			logger.error("Cache删除失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 验证该值，在hash中是否存在。
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public Boolean existsHash(Object key, Object field) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			Boolean result = jedisCluster.hexists(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
			return result;
		} catch (Exception e) {
			logger.error("Cache验证hash 是否存在该值失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 拿到缓存中所有符合pattern的key
	 * 
	 * @param pattern
	 * @return
	 */
	public Set<byte[]> keys(String pattern) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			Set<byte[]> allKey = jedisCluster.hkeys(("*" + pattern + "*").getBytes());
			return allKey;
		} catch (Exception e) {
			logger.error("Cache获取失败：", e);
			return new HashSet<byte[]>();
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 获得hash中的所有key value
	 * 
	 * @param key
	 * @return
	 */
	public Map<byte[], byte[]> getAllHash(Object key) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			Map<byte[], byte[]> map = jedisCluster.hgetAll(SerializeUtils.serialize(key));
			return map;
		} catch (Exception e) {
			logger.error("Cache获取失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 获得hash中的所有 values
	 * 
	 * @param key
	 * @return
	 */
	public List<String> getAllValues(Object key) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			List<String> list = jedisCluster.hvals(String.valueOf(key));
			return list;
		} catch (Exception e) {
			logger.error("Cache获取失败：", e);
			return null;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 判断一个key是否存在
	 * 
	 * @param key
	 * @return
	 */
	public Boolean exists(Object key) {

		Boolean result = false;

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			result = jedisCluster.exists(SerializeUtils.serialize(key));
			return result;
		} catch (Exception e) {
			logger.error("Cache获取失败：", e);
			return false;
		} finally {
			releaseResource(jedisCluster);
		}
	}

	/**
	 * 获取Redis中的key 的 ttl
	 * 
	 * @param jedisCluster
	 * @throws Exception
	 */
	public long getTtl(String key) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		try {
			return jedisCluster.ttl(key);
		} catch (Exception e) {
			logger.error("Cache获取ttl失败：", e);
		} finally {
			releaseResource(jedisCluster);
		}
		return 0;
	}

	
	
	private static final String LOCK_NODE ="LOCK";
	private static final String LOCK_SUCCESS = "OK";
	private static final String SET_IF_NOT_EXIST = "NX";
	private static final String SET_WITH_EXPIRE_TIME = "PX";

	/**
	 * 尝试获取分布式锁
	 * 
	 * @param jedis      Redis客户端
	 * @param requestId  请求标识（随机数）
	 * @param expireTime 超期时间
	 * @return 是否获取成功
	 */
	public boolean tryGetDistributedLock(String requestId, int expireTime) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		String result = jedisCluster.set(LOCK_NODE, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

		if (LOCK_SUCCESS.equals(result)) {
			return true;
		}
		return false;
	}

	private static final Long RELEASE_SUCCESS = 1L;

	/**
	 * 释放分布式锁
	 * 
	 * @param jedis     Redis客户端
	 * @param requestId 请求标识（随机数）
	 * @return 是否释放成功
	 */
	public boolean releaseDistributedLock(String requestId) {

		jedisCluster = JedisClusterInstance.newjedisClusterInstance() ;
		
		String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
		Object result = jedisCluster.eval(script, Collections.singletonList(LOCK_NODE), Collections.singletonList(requestId));

		if (RELEASE_SUCCESS.equals(result)) {
			return true;
		}
		return false;
	}
	
	
	
	

	

}
